import {hasOwn, isDef} from "../../../shared/util";
import {isRealNode} from "../../../core/vdom/utils";
import {VIRTUAL_NODE_TYPE} from "../../../constant";

// 字母大小写映射表
const AlphaMap = {
    'a': 'A',
    'b': 'B',
    'c': 'C',
    'd': 'D',
    'e': 'E',
    'f': 'F',
    'g': 'G',
    'h': 'H',
    'i': 'I',
    'j': 'J',
    'k': 'K',
    'l': 'L',
    'm': 'M',
    'n': 'N',
    'o': 'O',
    'p': 'P',
    'q': 'Q',
    'r': 'R',
    's': 'S',
    't': 'T',
    'u': 'U',
    'v': 'V',
    'w': 'W',
    'x': 'X',
    'y': 'Y',
    'z': 'Z'
};

/**
 * 将 html 写法转换为 JS 写法
 * 例子: padding-top => paddingTop
 * @param {String} property
 */
function translateProperty (property) {
    let index = -1;
    do {
        // 获取 - 的位置
        index = property.indexOf('-');
        // 改变字符串
        property[index+1] = AlphaMap[property[index+1]];
    } while (index !== -1);
    // 删除全部 # 号
    property = property.replaceAll('#', '');
    return property;
}

/**
 * 组装 vnode 节点中的静态 style 属性与动态 style 属性
 * @param {HTMLElement | VNode} vnode
 * @return {Object}
 */
function getStyle (vnode) {

    if (vnode.nodeType !== VIRTUAL_NODE_TYPE.ELEMENT) {
        return;
    }

    const styleList = {};

    if (!isRealNode(vnode)) {
        let staticStyleStr = "";
        let bindStyleObj = null;

        // 如果是根节点, 需要获取组件占位节点的静态 CSS style 字符串
        if (vnode.context.vnode === vnode) {
            // 获取组件实例
            const context = vnode.context;
            // 查看组件属性中是否存在 style 属性
            if (hasOwn(context, 'style') && isDef(context.style)) {
                const componentVNodeStyle = context.style;
                componentVNodeStyle.split(';').forEach(function (stylePair) {
                    if (stylePair.trim().length !== 0) {
                        const matchResult = /([a-zA-Z_]+)\s*:\s*([-a-zA-Z0-9]+)/.exec(stylePair);
                        const property = matchResult[1];
                        const value = matchResult[2];
                        styleList[property] = value;
                    }
                });
            }
        }

        // fixme 先不实现组件动态 style 的绑定
        // todo 如果有时间,实现组件动态 style 的绑定

        // 获取静态 CSS style 字符串
        if (isDef(vnode.data.attrs.style)) {
            staticStyleStr = vnode.data.attrs.style;
            // 处理静态字符串
            staticStyleStr.split(';').forEach(function (stylePair) {
                if (stylePair.trim().length !== 0) {
                    const matchResult = /([a-zA-Z_]+)\s*:\s*([-a-zA-Z0-9]+)/.exec(stylePair);
                    const property = matchResult[1];
                    const value = matchResult[2];
                    styleList[property] = value;
                }
            });
            vnode.data.staticStyle = vnode.data.attrs.style;
            // delete vnode.data.attrs.style;
        }

        // 获取动态 CSS style 字符串
        if (isDef(vnode.data.bindAttrs) && isDef(vnode.data.bindAttrs.style)) {
            bindStyleObj = vnode.data.bindAttrs.style;
            // 处理动态对象
            Object.keys(bindStyleObj).forEach(function (property) {
                styleList[property] = bindStyleObj[property];
            });
            vnode.data.bindStyle = vnode.data.bindAttrs.style;
            // delete vnode.data.bindAttrs.style;
        }
    }

    return styleList;
}

function updateStyle (oldNode, newNode) {
    const oldStyleObj = getStyle(oldNode);
    const newStyleObj = getStyle(newNode);

    let elem = null;
    isRealNode(oldNode)
        ? elem = oldNode
        : elem = newNode.elem;

    // 删除 newStyleObj 中没有的 style 属性
    for (let property in oldStyleObj) {
        if (!hasOwn(newStyleObj, property)) {
            elem.style[property] = '';
        }
    }

    // 设置 newStyleObj 中的 style 属性
    for (let property in newStyleObj) {
        if (!hasOwn(oldStyleObj, property)) {
            elem.style[property] = newStyleObj[property];
        }
        else {
            const oldValue = oldStyleObj[property];
            const newValue = newStyleObj[property];
            if (oldValue !== newValue) {
                elem.style[property] = newStyleObj[property];
            }
        }
    }
}

export default {
    mount: updateStyle,
    update: updateStyle
};
